package com.bigknow.appstore.web.console.controller;

import com.alibaba.fastjson.JSON;
import com.bigknow.appstore.proxy.entity.ProxyMeta;
import com.bigknow.appstore.web.base.entity.AuditLog;
import com.bigknow.appstore.web.base.entity.User;
import com.bigknow.appstore.web.base.service.IFusionService;
import com.bigknow.appstore.web.base.vo.FancyTreeVo;
import com.bigknow.appstore.web.console.app.Application;
import com.bigknow.appstore.web.console.app.ApplicationCategory;
import com.bigknow.appstore.web.console.app.ApplicationState;
import com.bigknow.appstore.web.console.app.RecommendBanner;
import com.bigknow.appstore.web.console.service.IApplicationService;
import com.bigknow.appstore.web.console.service.impl.ApplicationCategoryService;
import com.bigknow.appstore.web.console.service.impl.ApplicationService;
import com.bigknow.appstore.web.console.vo.ApplicationVo;
import com.bigknow.appstore.web.framework.controller.AbstractRestController;
import com.bigknow.appstore.web.framework.util.GlobalConstant;
import com.bigknow.appstore.web.framework.vo.Page;
import com.bigknow.appstore.web.framework.vo.ResultInfo;
import com.bigknow.appstore.web.framework.vo.VoFactory;
import com.bigknow.appstore.web.util.UploadFileUtils;
import com.bigknow.fusion.common.inf.server.appstore.FusionHandler;
import com.bigknow.fusion.common.model.appstore.DataService;
import com.bigknow.net.minidev.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.bouncycastle.math.raw.Mod;
import org.mongodb.morphia.Datastore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.servlet.ModelAndView;

import java.util.*;
import java.util.stream.Collectors;

import static com.bigknow.appstore.web.framework.util.GlobalConstant.PUBLISH_APPLYED;
import static com.bigknow.appstore.web.framework.util.GlobalConstant.PUBLISH_NONE;
import static com.bigknow.appstore.web.framework.util.GlobalConstant.RETIRE_SUCCESS;
import static com.bigknow.appstore.web.framework.util.GlobalConstant.RETIRE_NONE;
import static com.bigknow.appstore.web.framework.util.GlobalConstant.REVOKE_SUCCESS;
import static com.bigknow.appstore.web.framework.util.GlobalConstant.REVOKE_NONE;


/**
 * Created by 李科风 on 2016-09-20.
 */
@RestController
@RequestMapping("/console/app")
public class ApplicationController extends AbstractRestController<Application, IApplicationService> {

    @Autowired
    private ApplicationCategoryService categoryService;

    @Autowired
    private IFusionService fusionService;

    @Override
    protected String getBasePath() {
        return "/console";
    }

    @Override
    protected String getBaseName() {
        return "app";
    }

    @RequestMapping
    public ModelAndView index() {
        ModelAndView mv = new ModelAndView("/console/app/appIndex");

        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        Application application = new Application();
        application.setUserId(user.getId());

        List<Application> apps = service.findWithFuzzy(application);

        mv.getModel().put("totalApp", apps.size());
        mv.getModel().put("testApp", apps.stream().filter(a -> {
            return a.getState() == ApplicationState.TEST;
        }).count());
        mv.getModel().put("applyingApp", apps.stream().filter(a -> {
            return a.getState() == ApplicationState.APPLYING;
        }).count());
        mv.getModel().put("publishedApp", apps.stream().filter(a -> {
            return a.getState() == ApplicationState.PUBLISHED;
        }).count());
        mv.getModel().put("deprecatedApp", apps.stream().filter(a -> {
            return a.getState() == ApplicationState.DEPRECATED;
        }).count());
        return mv;
    }

    @RequestMapping(value = "/list/{state}")
    public ModelAndView listByState(Application application, @PathVariable String state, Integer pageIndex, Integer pageSize) {
        if (!StringUtils.isEmpty(state)) {
            application.setState(ApplicationState.valueOf(state));
        }
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        application.setUserId(user.getId());

        pageIndex = (pageIndex == null) ? GlobalConstant.DEFAULT_PAGE_INDEX : pageIndex;
        pageSize = (pageSize == null) ? GlobalConstant.DEFAULT_PAGE_SIZE : pageSize;

        ModelAndView modelAndView = super.list(application, pageIndex, pageSize);
        ModelMap map = modelAndView.getModelMap();
        if (map != null) {
            List<Application> apps = (List<Application>) ((Page) map.get("page")).getEntities();
            for (Application app : apps) {
                app.setCategory(categoryService.getCategory(app.getCategoryId()));
            }
        }
        return modelAndView;
    }

    @RequestMapping("/getServiceTree")
    protected List<FancyTreeVo> getServiceTree(@RequestParam("id") String id) {
        List<String> ids = new ArrayList<>();
        if (!StringUtils.isEmpty(id)) {
            Application app = service.get(id);
            if (app != null && app.getServiceIds() != null) {
                ids.addAll(app.getServiceIds());
            }
        }

        User user = (User) SecurityUtils.getSubject().getPrincipal();
        List<FancyTreeVo> res = new ArrayList<>();
        FusionHandler handler = fusionService.getFusionHandler();
        List<DataService> services = handler.getDataService(user.getId());

        FancyTreeVo serviceRoot = new FancyTreeVo("dataService", "数据服务");
        serviceRoot.setFolder(true);
        serviceRoot.setExpanded(true);
        res.add(serviceRoot);

        for (DataService dataService : services) {
            FancyTreeVo serviceNode = new FancyTreeVo(dataService.getId(), dataService.getName());
            serviceNode.setSelected(ids.contains(dataService.getId()));
            serviceRoot.getChildren().add(serviceNode);
        }

        return res;
    }

    @RequestMapping(value = "/retire")
    public ResultInfo retire(String id) {
        try {
            if (service.retire(id) == 0) {
                return VoFactory.newResultInfo(ResultInfo.ERROR, springUtils.getMessage(RETIRE_NONE));
            }
            auditLogService.add(id, service.getAppName(id), "应用下架", ApplicationController.class, AuditLog.OperationType.RETIRE);
        } catch (Exception e) {
            return VoFactory.newResultInfo(ResultInfo.ERROR, e.getMessage());
        }
        return VoFactory.newResultInfo(ResultInfo.SUCCESS, springUtils.getMessage(RETIRE_SUCCESS));
    }

    @RequestMapping(value = "/publish")
    public ResultInfo publish(String id) {
        try {
            if (service.publish(id) == 0) {
                return VoFactory.newResultInfo(ResultInfo.ERROR, springUtils.getMessage(PUBLISH_NONE));
            }
            auditLogService.add(id, service.getAppName(id), "应用申请发布成功", ApplicationController.class, AuditLog.OperationType.PUBLISH);
        } catch (Exception e) {
            return VoFactory.newResultInfo(ResultInfo.ERROR, e.getMessage());
        }
        return VoFactory.newResultInfo(ResultInfo.SUCCESS, springUtils.getMessage(PUBLISH_APPLYED));
    }

    @RequestMapping(value = "/cancelPublish")
    public ResultInfo cancelPublish(String id) {
        try {
            if (service.cancelPublish(id) == 0) {
                return VoFactory.newResultInfo(ResultInfo.ERROR, springUtils.getMessage(REVOKE_NONE));
            }
            auditLogService.add(id, service.getAppName(id), "应用发布取消", ApplicationController.class, AuditLog.OperationType.REVOKE);
        } catch (Exception e) {
            return VoFactory.newResultInfo(ResultInfo.ERROR, e.getMessage());
        }
        return VoFactory.newResultInfo(ResultInfo.SUCCESS, springUtils.getMessage(REVOKE_SUCCESS));
    }

    @RequestMapping(value = "rest/appUrl/{id}", method = RequestMethod.GET)
    public String getAppUrl(@PathVariable String id) {
        return service.getUrl(id);
    }

    @RequestMapping("/getApplication")
    public ModelAndView getApplication(@RequestParam("id") String id) {
        Map<String, Object> model = new HashMap<>();
        Application app = service.get(id);
        model.put("app", app);
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        model.put("user", user);
        FusionHandler handler = fusionService.getFusionHandler();
        List<DataService> services = handler.getDataService(user.getId());
        model.put("services", services.stream().filter(ser -> {
            return app.getServiceIds().contains(ser.getId());
        }).collect(Collectors.toList()));

        logger.info("applicationApp:{}",JSON.toJSONString(app));
        ModelAndView mv = new ModelAndView("/console/app/appDetail", model);
        return mv;
    }

    @RequestMapping(value = "/rest/insertApplication", method = RequestMethod.POST)
    public ResultInfo insertApplication(ApplicationVo vo) {
        try {
            CommonsMultipartFile logoFile = vo.gettLogoFile();
            String fileName = UploadFileUtils.saveImage(logoFile, "/resource/app", UUID.randomUUID().toString(), imgFile -> {
                if (imgFile.getWidth() != 72 || imgFile.getHeight() != 72) {
                    throw new RuntimeException("Logo大小必须为72px*72px");
                }
                return true;
            });
            vo.setLogoFile(fileName);
            List<CommonsMultipartFile> sfs = vo.gettScreenshotFile();
            List<String> files = new ArrayList<>();
            for (CommonsMultipartFile sf : sfs) {
                if (sf.isEmpty()) {
                    continue;
                }
                fileName = UploadFileUtils.saveImage(sf, "/resource/app", UUID.randomUUID().toString(), imgFile -> {
                    if (imgFile.getWidth() != 330 || imgFile.getHeight() != 450) {
                        throw new RuntimeException("应用截图大小必须为330*450px");
                    }
                    return true;
                });
                files.add(fileName);
            }
            vo.setScreenshotFiles(files);
        } catch (Exception e) {
            return VoFactory.newResultInfo(ResultInfo.ERROR, e.getMessage());
        }

        return super.insert(vo);
    }

    @RequestMapping(value = "/rest/updateApplication", method = RequestMethod.POST)
    public ResultInfo updateApplication(ApplicationVo vo) {
        try {
            Application old = service.get(vo.getId());
            CommonsMultipartFile logoFile = vo.gettLogoFile();
            if (logoFile != null && !logoFile.isEmpty()) {
                String fileName = UploadFileUtils.saveImage(logoFile, "/resource/app", UUID.randomUUID().toString(), imgFile -> {
                    if (imgFile.getWidth() != 72 || imgFile.getHeight() != 72) {
                        throw new RuntimeException("Logo大小必须为72px*72px");
                    }
                    return true;
                });

                UploadFileUtils.deleteImage("/resource/app", old.getLogoFile());
                vo.setLogoFile(fileName);
            } else {
                vo.setLogoFile(old.getLogoFile());
            }
            List<CommonsMultipartFile> sfs = vo.gettScreenshotFile();
            if (!sfs.isEmpty() && !sfs.get(0).isEmpty()) {
                List<String> files = new ArrayList<>();
                for (CommonsMultipartFile sf : sfs) {
                    if (sf.isEmpty()) {
                        continue;
                    }
                    String fileName = UploadFileUtils.saveImage(sf, "/resource/app", UUID.randomUUID().toString(), imgFile -> {
                        if (imgFile.getWidth() != 330 || imgFile.getHeight() != 450) {
                            throw new RuntimeException("应用截图大小必须为330*450px");
                        }
                        return true;
                    });
                    files.add(fileName);
                }

                for (String oldFile : old.getScreenshotFiles()) {
                    UploadFileUtils.deleteImage("/resource/app", oldFile);
                }
                vo.setScreenshotFiles(files);
            } else {
                vo.setScreenshotFiles(old.getScreenshotFiles());
            }
        } catch (Exception e) {
            return VoFactory.newResultInfo(ResultInfo.ERROR, e.getMessage());
        }

        return super.update(vo);
    }
}
